APB3 definition
Introduction
This example will show the syntax to define an APB3 Bundle
.
Specification
The specification from ARM could be interpreted as follows:
Signal Name |
Type |
Driver side |
Comment |
---|---|---|---|
PADDR |
UInt(addressWidth bits) |
Master |
Address in byte |
PSEL |
Bits(selWidth) |
Master |
One bit per slave |
PENABLE |
Bool |
Master |
|
PWRITE |
Bool |
Master |
|
PWDATA |
Bits(dataWidth bits) |
Master |
|
PREADY |
Bool |
Slave |
|
PRDATA |
Bits(dataWidth bits) |
Slave |
|
PSLVERROR |
Bool |
Slave |
Optional |
Implementation
This specification shows that the APB3 bus has multiple possible configurations. To represent that, we can define a configuration class in Scala:
case class Apb3Config(
addressWidth : Int,
dataWidth : Int,
selWidth : Int = 1,
useSlaveError : Boolean = true
)
Then we can define the APB3 Bundle
which will be used to represent the bus in hardware:
case class Apb3(config: Apb3Config) extends Bundle with IMasterSlave {
val PADDR = UInt(config.addressWidth bit)
val PSEL = Bits(config.selWidth bits)
val PENABLE = Bool
val PREADY = Bool
val PWRITE = Bool
val PWDATA = Bits(config.dataWidth bit)
val PRDATA = Bits(config.dataWidth bit)
val PSLVERROR = if(config.useSlaveError) Bool else null
override def asMaster(): Unit = {
out(PADDR,PSEL,PENABLE,PWRITE,PWDATA)
in(PREADY,PRDATA)
if(config.useSlaveError) in(PSLVERROR)
}
}
Usage
Here is a usage example of this definition:
val apbConfig = Apb3Config(
addressWidth = 16,
dataWidth = 32,
selWidth = 1,
useSlaveError = false
)
val io = new Bundle{
val apb = slave(Apb3(apbConfig))
}
io.apb.PREADY := True
when(io.apb.PSEL(0) && io.apb.PENABLE){
//...
}